home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Source / GNU / emacs / src / filelock.c < prev    next >
C/C++ Source or Header  |  1992-08-07  |  10KB  |  429 lines

  1. /* Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
  2.  
  3. This file is part of GNU Emacs.
  4.  
  5. GNU Emacs is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 1, or (at your option)
  8. any later version.
  9.  
  10. GNU Emacs is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with GNU Emacs; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19.  
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include "config.h"
  23. #ifdef hpux
  24. /* needed by <pwd.h> */
  25. #include <stdio.h>
  26. #undef NULL
  27. #endif
  28. #include "lisp.h"
  29. #include "paths.h"
  30. #include "buffer.h"
  31.  
  32. #ifdef VMS
  33. #include "vms-pwd.h"
  34. #else
  35. #include <pwd.h>
  36. #endif
  37.  
  38. #include <errno.h>
  39. #include <sys/file.h>
  40. #ifdef USG
  41. #include <fcntl.h>
  42. #endif /* USG */
  43.  
  44. #include "filetypes.h"
  45.  
  46. extern int errno;
  47.  
  48. #ifdef VMS
  49. /* Prevent the file from being totally empty.  */
  50. static dummy () {}
  51. #endif
  52.  
  53. #ifdef CLASH_DETECTION
  54.   
  55. /* If system does not have symbolic links, it does not have lstat.
  56.    In that case, use ordinary stat instead.  */
  57.  
  58. #ifndef S_IFLNK
  59. #define lstat stat
  60. #endif
  61.  
  62. static Lisp_Object
  63. lock_file_owner_name (lfname)
  64.      char *lfname;
  65. {
  66.   struct stat s;
  67.   struct passwd *the_pw;
  68.   extern struct passwd *getpwuid ();
  69.  
  70.   if (lstat (lfname, &s) == 0)
  71.     the_pw = getpwuid (s.st_uid);
  72.   return (the_pw == 0 ? Qnil : build_string (the_pw->pw_name));
  73. }
  74.  
  75.  
  76. /* lock_file locks file fn,
  77.    meaning it serves notice on the world that you intend to edit that file.
  78.    This should be done only when about to modify a file-visiting
  79.    buffer previously unmodified.
  80.    Do not (normally) call lock_buffer for a buffer already modified,
  81.    as either the file is already locked, or the user has already
  82.    decided to go ahead without locking.
  83.  
  84.    When lock_buffer returns, either the lock is locked for us,
  85.    or the user has said to go ahead without locking.
  86.  
  87.    If the file is locked by someone else, lock_buffer calls
  88.    ask-user-about-lock (a Lisp function) with two arguments,
  89.    the file name and the name of the user who did the locking.
  90.    This function can signal an error, or return t meaning
  91.    take away the lock, or return nil meaning ignore the lock.  */
  92.  
  93. /* The lock file name is the file name with "/" replaced by "!"
  94.    and put in the Emacs lock directory.  */
  95. /* (ie., /ka/king/junk.tex -> /!/!ka!king!junk.tex). */
  96.  
  97. /* If SHORT_FILE_NAMES is defined, the lock file name is the hex
  98.    representation of a 14-bytes CRC generated from the file name
  99.    and put in the Emacs lock directory (not very nice, but it works).
  100.    (ie., /ka/king/junk.tex -> /!/ec92d3ed24a8f0). */
  101.  
  102. #ifdef SHORT_FILE_NAMES
  103.  
  104. # define CREATE_LOCK_FILE_NAME(lfname, fn) \
  105.   { lfname = (char *) alloca (14 + strlen (PATH_LOCK) + 1); \
  106.   fill_in_lock_short_file_name (lfname, fn); }
  107.  
  108. #else
  109.  
  110. # define CREATE_LOCK_FILE_NAME(lfname, fn) \
  111.   { lfname = (char *) alloca (XSTRING (fn)->size + strlen (PATH_LOCK) + 1); \
  112.   fill_in_lock_file_name (lfname, fn); }
  113.  
  114. #endif
  115.  
  116.  
  117.  
  118. void
  119. lock_file (fn)
  120.      register Lisp_Object fn;
  121. {
  122.   register Lisp_Object attack;
  123.   register char *lfname;
  124.  
  125.   /* Create the name of the lock-file for file fn */
  126.   CREATE_LOCK_FILE_NAME (lfname, fn);
  127.  
  128.   /* See if this file is visited and has changed on disk since it was visited.  */
  129.   {
  130.     register Lisp_Object subject_buf = Fget_file_buffer (fn);
  131.     if (!NULL (subject_buf)
  132.     && NULL (Fverify_visited_file_modtime (subject_buf))
  133.     && !NULL (Ffile_exists_p (fn)))
  134.       call1 (intern ("ask-user-about-supersession-threat"), fn);
  135.   }
  136.  
  137.   /* Try to lock the lock. */
  138.   if (lock_if_free (lfname) <= 0)
  139.     /* Return now if we have locked it, or if lock dir does not exist */
  140.     return;
  141.  
  142.   /* Else consider breaking the lock */
  143.   attack = call2 (intern ("ask-user-about-lock"), fn,
  144.           lock_file_owner_name (lfname));
  145.   if (!NULL (attack))
  146.     /* User says take the lock */
  147.     {
  148.       lock_superlock (lfname);
  149.       lock_file_1 (lfname, O_WRONLY) ;
  150.       unlink (PATH_SUPERLOCK);
  151.       return;
  152.     }
  153.   /* User says ignore the lock */
  154. }
  155.  
  156. fill_in_lock_file_name (lockfile, fn)
  157.      register char *lockfile;
  158.      register Lisp_Object fn;
  159. {
  160.   register char *p;
  161.  
  162.   strcpy (lockfile, PATH_LOCK);
  163.  
  164.   p = lockfile + strlen (lockfile);
  165.  
  166.   strcpy (p, XSTRING (fn)->data);
  167.  
  168.   for (; *p; p++)
  169.     {
  170.       if (*p == '/')
  171.     *p = '!';
  172.     }
  173. }
  174.  
  175. #ifdef SHORT_FILE_NAMES
  176. fill_in_lock_short_file_name (lockfile, fn)
  177.      register char *lockfile;
  178.      register Lisp_Object fn;
  179. {
  180.   register union
  181.     {
  182.       unsigned int  word [2];
  183.       unsigned char byte [8];
  184.     } crc;
  185.   register unsigned char *p, new;
  186.   
  187.   /* 7-bytes cyclic code for burst correction on byte-by-byte basis.
  188.      the used polynomial is D^7 + D^6 + D^3 +1. pot@fdt.CNUCE.CNR.IT */
  189.  
  190.   crc.word[0] = crc.word[1] = 0;
  191.  
  192.   for (p = XSTRING (fn)->data; new = *p++; )
  193.     {
  194.       new += crc.byte[7];
  195.       crc.byte[7] = crc.byte[6];
  196.       crc.byte[6] = crc.byte[5] + new;
  197.       crc.byte[5] = crc.byte[4];
  198.       crc.byte[4] = crc.byte[3];
  199.       crc.byte[3] = crc.byte[2] + new;
  200.       crc.byte[2] = crc.byte[1];
  201.       crc.byte[1] = crc.byte[0];
  202.       crc.byte[0] = new;
  203.     }
  204.   sprintf (lockfile, "%s%.2x%.2x%.2x%.2x%.2x%.2x%.2x", PATH_LOCK,
  205.        crc.byte[0], crc.byte[1], crc.byte[2], crc.byte[3],
  206.        crc.byte[4], crc.byte[5], crc.byte[6]);
  207. }
  208. #endif /* SHORT_FILE_NAMES */
  209.  
  210. /* Lock the lock file named LFNAME.
  211.    If MODE is O_WRONLY, we do so even if it is already locked.
  212.    If MODE is O_WRONLY | O_EXCL | O_CREAT, we do so only if it is free.
  213.    Return 1 if successful, 0 if not.  */
  214.  
  215. int
  216. lock_file_1 (lfname, mode)
  217.      int mode; char *lfname; 
  218. {
  219.   register int fd;
  220.   char buf[20];
  221.  
  222.   if ((fd = open (lfname, mode, 0666)) >= 0)
  223.     {
  224. #ifdef NO_FCHMOD
  225.       chmod (lfname, 0666);
  226. #else
  227.       fchmod (fd, 0666);
  228. #endif
  229.       sprintf (buf, "%d ", getpid ());
  230.       write (fd, buf, strlen (buf));
  231.       close (fd);
  232.       return 1;
  233.     }
  234.   else
  235.     return 0;
  236. }
  237.  
  238. /* Lock the lock named LFNAME if possible.
  239.    Return 0 in that case.
  240.    Return positive if lock is really locked by someone else.
  241.    Return -1 if cannot lock for any other reason.  */
  242.  
  243. int
  244. lock_if_free (lfname)
  245.      register char *lfname; 
  246. {
  247.   register int clasher;
  248.  
  249.   while (lock_file_1 (lfname, O_WRONLY | O_EXCL | O_CREAT) == 0)
  250.     {
  251.       if (errno != EEXIST)
  252.     return -1;
  253.       clasher = current_lock_owner (lfname);
  254.       if (clasher != 0)
  255.     if (clasher != getpid ())
  256.       return (clasher);
  257.     else return (0);
  258.       /* Try again to lock it */
  259.     }
  260.   return 0;
  261. }
  262.  
  263. /* Return the pid of the process that claims to own the lock file LFNAME,
  264.    or 0 if nobody does or the lock is obsolete,
  265.    or -1 if something is wrong with the locking mechanism.  */
  266.  
  267. int
  268. current_lock_owner (lfname)
  269.      char *lfname;
  270. {
  271.   int owner = current_lock_owner_1 (lfname);
  272.   if (owner == 0 && errno == ENOENT)
  273.     return (0);
  274.   /* Is it locked by a process that exists?  */
  275.   if (owner != 0 && (kill (owner, 0) >= 0 || errno == EPERM))
  276.     return (owner);
  277.   if (unlink (lfname) < 0)
  278.     return (-1);
  279.   return (0);
  280. }
  281.  
  282. int
  283. current_lock_owner_1 (lfname)
  284.      char *lfname;
  285. {
  286.   register int fd;
  287.   char buf[20];
  288.   int tem;
  289.  
  290.   fd = open (lfname, O_RDONLY, 0666);
  291.   if (fd < 0)
  292.     return 0;
  293.   tem = read (fd, buf, sizeof buf);
  294.   close (fd);
  295.   return (tem <= 0 ? 0 : atoi (buf));
  296. }
  297.  
  298.  
  299. void
  300. unlock_file (fn)
  301.      register Lisp_Object fn;
  302. {
  303.   register char *lfname;
  304.  
  305.   CREATE_LOCK_FILE_NAME (lfname, fn);
  306.  
  307.   lock_superlock (lfname);
  308.  
  309.   if (current_lock_owner_1 (lfname) == getpid ())
  310.     unlink (lfname);
  311.  
  312.   unlink (PATH_SUPERLOCK);
  313. }
  314.  
  315. lock_superlock (lfname)
  316.      char *lfname;
  317. {
  318.   register int i, fd;
  319.  
  320.   for (i = -20; i < 0 && (fd = open (PATH_SUPERLOCK,
  321.                      O_WRONLY | O_EXCL | O_CREAT, 0666)) < 0;
  322.        i++)
  323.     {
  324.       if (errno != EEXIST)
  325.     return;
  326.       sleep (1);
  327.     }
  328.   if (fd >= 0)
  329.     {
  330. #ifdef NO_FCHMOD
  331.       chmod (PATH_SUPERLOCK, 0666);
  332. #else
  333.       fchmod (fd, 0666);
  334. #endif
  335.       write (fd, lfname, strlen (lfname));
  336.       close (fd);
  337.     }
  338. }
  339.  
  340. void
  341. unlock_all_files ()
  342. {
  343.   register Lisp_Object tail;
  344.   register struct buffer *b;
  345.  
  346.   for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
  347.        tail = XCONS (tail)->cdr)
  348.     {
  349.       b = XBUFFER (XCONS (XCONS (tail)->car)->cdr);
  350.       if (XTYPE (b->filename) == Lisp_String &&
  351.       b->save_modified < BUF_MODIFF (b))
  352.     unlock_file (b->filename);
  353.     }
  354. }
  355.  
  356.  
  357. DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
  358.   0, 1, 0,
  359.   "Locks FILE, if current buffer is modified.\n\
  360. FILE defaults to current buffer's visited file,\n\
  361. or else nothing is done if current buffer isn't visiting a file.")
  362.   (fn)
  363.      Lisp_Object fn;
  364. {
  365.   if (NULL (fn))
  366.     fn = current_buffer->filename;
  367.   else
  368.     CHECK_STRING (fn, 0);
  369.   if (current_buffer->save_modified < MODIFF
  370.       && !NULL (fn))
  371.     lock_file (fn);
  372.   return Qnil;    
  373. }
  374.  
  375. DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
  376.   0, 0, 0,
  377.  "Unlocks the file visited in the current buffer,\n\
  378. if it should normally be locked.")
  379.   ()
  380. {
  381.   if (current_buffer->save_modified < MODIFF &&
  382.       XTYPE (current_buffer->filename) == Lisp_String)
  383.     unlock_file (current_buffer->filename);
  384.   return Qnil;
  385. }
  386.  
  387.  
  388. /* Unlock the file visited in buffer BUFFER.  */
  389.  
  390. unlock_buffer (buffer)
  391.      struct buffer *buffer;
  392. {
  393.   if (buffer->save_modified < BUF_MODIFF (buffer)
  394.       && XTYPE (buffer->filename) == Lisp_String)
  395.     unlock_file (buffer->filename);
  396. }
  397.  
  398. DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0,
  399.   "Returns nil if the FILENAME is not locked,\n\
  400. t if it is locked by you, else a string of the name of the locker.")
  401.   (fn)
  402.   Lisp_Object fn;
  403. {
  404.   register char *lfname;
  405.   int owner;
  406.  
  407.   fn = Fexpand_file_name (fn, Qnil);
  408.  
  409.   /* Create the name of the lock-file for file filename */
  410.   CREATE_LOCK_FILE_NAME (lfname, fn);
  411.  
  412.   owner = current_lock_owner (lfname);
  413.   if (owner <= 0)
  414.     return (Qnil);
  415.   else if (owner == getpid ())
  416.     return (Qt);
  417.   
  418.   return (lock_file_owner_name (lfname));
  419. }
  420.  
  421. syms_of_filelock ()
  422. {
  423.   defsubr (&Sunlock_buffer);
  424.   defsubr (&Slock_buffer);
  425.   defsubr (&Sfile_locked_p);
  426. }
  427.  
  428. #endif /* CLASH_DETECTION */
  429.